package com.example.demo.mathtest;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;

import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;


public class Questions {
    int grade; //年级
    int intResult = 0; // 整数答案
    Rational raResult = null; // 分数答案
    Double douResult = 0.0;   //小数答案

    public ArrayList<TM> questionArrayList = new ArrayList<>();    //题目和正确答案列表
    public ArrayList<TM> errorQuestionList = new ArrayList<>();   //错误的题目保存的列表

    final int intAddSub = 1, intMulDiv = 2, DecAddSub = 3, DecMulDiv = 4,
            DecCmp = 5, RaAddSub = 6, RaMulDiv = 7, RaCmp = 8, ARITH = 9;

    public Questions(int grade) {
        this.grade = grade;
    }

    //0到max范围内生成随机数
    public int createRandomNumber(int max) {
        Random random = new Random();
        return random.nextInt(max);
    }

    //生成指定位数小数,scl为最大位数
    public double createRandomDecimal(int scl) {
        double min = 0.0001;//最小值
        double max = 10;//总和
        int pow = (int) Math.pow(10, scl);//指定小数位
        return Math.floor((Math.random() * (max - min) + min) * pow) / pow;
    }

    public char transformNum2Char(int num) {
        return num == 1 ? '<' : (num == 2 ? '>' : '=');
    }

    //算式列表的产生
    public void mathQuestionsCreate(int grade, int numberOfQuestions) throws Exception {
        int max;
        int i = 0;
        //题目的总数目
        while (i < numberOfQuestions) {
            TM tm = new TM();
            switch (grade) {
                case 1:
                    max = 10;
                    switch (createRandomNumber(2) % 2) {
                        case 0:
                            tm.setFormula(createAddQuestions(max));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            questionArrayList.add(i, tm);
                            break;
                        case 1:
                            tm.setFormula(createSubQuestions(max));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            questionArrayList.add(i, tm);
                            break;
                    }
                    tm.setType(intAddSub);
                    break;
                case 2:
                    max = 9;
                    switch (createRandomNumber(4) % 4) {
                        case 0:
                            tm.setFormula(createMulQuestions(max));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 1:
                            tm.setFormula(createDivQuestions(max));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 2:
                            tm.setFormula(createAddQuestions(100));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intAddSub);
                            questionArrayList.add(i, tm);
                            break;
                        case 3:
                            tm.setFormula(createSubQuestions(100));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intAddSub);
                            questionArrayList.add(i, tm);
                            break;
                    }
                    break;
                case 3:
                    max = 10;
                    switch (createRandomNumber(4) % 4) {
                        case 0:
                            tm.setFormula(createARITHQuestions());
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setType(ARITH);
                            tm.setOption(1);
                            questionArrayList.add(i, tm);
                            break;
                        case 1:
                            tm.setFormula(createRationalComp(max));
                            tm.setOption(intResult);
                            tm.setAnswer(tm.getFormula().replace('⚪', transformNum2Char(tm.getOption())));
                            tm.setType(RaCmp);
                            questionArrayList.add(i, tm);
                            break;
                        case 2:
                            tm.setFormula(createAddQuestions(100));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intAddSub);
                            questionArrayList.add(i, tm);
                            break;
                        case 3:
                            tm.setFormula(createSubQuestions(100));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intAddSub);
                            questionArrayList.add(i, tm);
                            break;
                    }
                    break;
                case 4:
                    max = 100;
                    switch (createRandomNumber(5) % 5) {
                        case 1:
                            tm.setFormula(createMulQuestions(max));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 0:
                            tm.setFormula(createDivQuestions(max));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 2:
                            tm.setFormula(createDecimalCmp());
                            tm.setOption(intResult);
                            tm.setAnswer(tm.getFormula().replace('⚪', transformNum2Char(tm.getOption())));
                            tm.setType(DecCmp);
                            questionArrayList.add(i, tm);
                            break;
                        case 3:
                            tm.setFormula(createAddQuestions(100));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intAddSub);
                            questionArrayList.add(i, tm);
                            break;
                        case 4:
                            tm.setFormula(createSubQuestions(100));
                            tm.setAnswer(String.valueOf(intResult));
                            tm.setOption(1);
                            tm.setType(intAddSub);
                            questionArrayList.add(i, tm);
                            break;
                    }
                    break;
                case 5:
                    max = 10;
                    switch (createRandomNumber(4) % 4) {
                        case 1:
                            tm.setFormula(createRationalAdd(max));
                            tm.setAnswer(String.valueOf(raResult));
                            tm.setOption(1);
                            tm.setType(RaAddSub);
                            questionArrayList.add(i, tm);
                            break;
                        case 0:
                            tm.setFormula(createRationalSub(max));
                            tm.setAnswer(String.valueOf(raResult));
                            tm.setOption(1);
                            tm.setType(RaAddSub);
                            questionArrayList.add(i, tm);
                            break;
                        case 2:
                            tm.setFormula(createDecimalAdd());
                            tm.setAnswer(String.valueOf(douResult));
                            tm.setOption(1);
                            tm.setType(DecAddSub);
                            questionArrayList.add(i, tm);
                            break;
                        case 3:
                            tm.setFormula(createDecimalSub());
                            tm.setAnswer(String.valueOf(douResult));
                            tm.setOption(1);
                            tm.setType(DecAddSub);
                            questionArrayList.add(i, tm);
                            break;
                    }
                    break;
                case 6:
                    max = 10;
                    switch (createRandomNumber(4) % 4) {
                        case 1:
                            tm.setFormula(createRationalMul(max));
                            tm.setAnswer(String.valueOf(raResult));
                            tm.setOption(1);
                            tm.setType(RaMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 0:
                            tm.setFormula(createRationalDiv(max));
                            tm.setAnswer(String.valueOf(raResult));
                            tm.setOption(1);
                            tm.setType(RaMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 2:
                            tm.setFormula(createDecimalMul());
                            tm.setAnswer(String.valueOf(douResult));
                            tm.setOption(1);
                            tm.setType(DecMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                        case 3:
                            tm.setFormula(createDecimalDiv());
                            tm.setAnswer(String.valueOf(douResult));
                            tm.setOption(1);
                            tm.setType(DecMulDiv);
                            questionArrayList.add(i, tm);
                            break;
                    }
                    break;
                default:
                    break;
            }
            i++;
        }
    }

    //生成一个加法的算式，并并返回结果
    private String createAddQuestions(int max) {
        int number;
        intResult = 0;
        number = createRandomNumber(max) + 1;
        intResult += number;
        String math_questions = String.valueOf(number);
        math_questions += " + ";
        number = createRandomNumber(max) + 1;
        math_questions += String.valueOf(number);
        math_questions += " = ";
        intResult += number;
        return math_questions;
    }

    //生成一个减法的算式，并并返回结果
    private String createSubQuestions(int max) {
        int numberFirst, numberSecond;
        String math_questions;
        numberFirst = createRandomNumber(max) + 1;
        numberSecond = createRandomNumber(max) + 1;
        if (numberFirst >= numberSecond) {
            math_questions = numberFirst + " - " + numberSecond + " = ";
            intResult = numberFirst - numberSecond;
        } else {
            math_questions = numberSecond + " - " + numberFirst + " = ";
            intResult = numberSecond - numberFirst;
        }
        return math_questions;
    }

    //生成一个乘法算式，并返回结果
    private String createMulQuestions(int max) {
        int numberFirst, numberSecond;
        String math_questions;
        numberFirst = createRandomNumber(max) + 1;
        numberSecond = createRandomNumber(max) + 1;
        math_questions = numberFirst + " × " + numberSecond + " = ";
        intResult = numberFirst * numberSecond;
        return math_questions;
    }

    //生成一个结果为整数的除法算式，并返回结果
    private String createDivQuestions(int max) {
        int numberFirst, numberSecond;
        String math_questions;
        intResult = createRandomNumber(max) + 1;
        numberSecond = createRandomNumber(max) + 1;
        numberFirst = intResult * numberSecond;
        math_questions = numberFirst + " ÷ " + numberSecond + " = ";
        return math_questions;
    }

    //生成一个四则运算公式,并返回结果
    private String createARITHQuestions() {
        BinaryTree bTree;
        String math_questions;
        Random random = new Random();
        int vim = random.nextInt(3) + 1;
        bTree = new BinaryTree(vim);
        bTree.createBTree();
        String res = bTree.CalAndVal();
        intResult = Integer.parseInt(res);
        while (intResult < 0)//过滤负数，小学3年级没学
        {
            bTree = new BinaryTree(vim);
            bTree.createBTree();
            res = bTree.CalAndVal();
            intResult = Integer.parseInt(res);
        }
        math_questions = bTree.toString();
        math_questions += "=";
        return math_questions;
    }

    // 生成两个随机分数
    private List<Rational> createTwoRandomRational(int max) throws Exception {
        int denominator1 = createRandomNumber(max);
        while (denominator1 == 0 || denominator1 == 1)
            denominator1 = createRandomNumber(max);
        int denominator2 = createRandomNumber(max);
        while (denominator2 == 0 || denominator2 == 1)
            denominator2 = createRandomNumber(max);
        int numerator1 = createRandomNumber(denominator1);
        while (numerator1 == 0)
            numerator1 = createRandomNumber(denominator1);
        int numerator2 = createRandomNumber(denominator2);
        while (numerator2 == 0)
            numerator2 = createRandomNumber(denominator2);
        List<Rational> resultList = new ArrayList<>();
        resultList.add(new Rational(numerator1, denominator1));
        resultList.add(new Rational(numerator2, denominator2));
        return resultList;
    }

    //生成比较分数大小的运算公式
    private String createRationalComp(int max) throws Exception {
        List<Rational> raList = createTwoRandomRational(max);
        int temp = raList.get(0).compareTo(raList.get(1));
        intResult = (temp > 0) ? 2 : (temp == 0 ? 3 : 1);//1:<  2: >  3:=
        String math_questions = "";
        math_questions += raList.get(0);
        math_questions += " ⚪ ";
        math_questions += raList.get(1);
        return math_questions;
    }

    //生成分数加法的运算公式
    private String createRationalAdd(int max) throws Exception {
        List<Rational> raList = createTwoRandomRational(max);
        String math_questions = raList.get(0) + " + " + raList.get(1) + " = ";
        raResult = raList.get(0).add(raList.get(1));
        return math_questions;
    }

    //生成分数减法的运算公式
    private String createRationalSub(int max) throws Exception {
        String math_questions;
        List<Rational> raList = createTwoRandomRational(max);
        if (raList.get(0).compareTo(raList.get(1)) >= 0) {
            math_questions = raList.get(0) + " - " + raList.get(1) + " = ";
            raResult = raList.get(0).subtract(raList.get(1));
        } else {
            math_questions = raList.get(1) + " - " + raList.get(0) + " = ";
            raResult = raList.get(1).subtract(raList.get(0));
        }
        return math_questions;
    }

    //生成分数乘法的运算公式
    private String createRationalMul(int max) throws Exception {
        List<Rational> raList = createTwoRandomRational(max);
        String math_questions;
        math_questions = raList.get(0) + " × " + raList.get(1) + " = ";
        raResult = raList.get(0).multiply(raList.get(1));
        return math_questions;
    }

    //生成分数除法的运算公式
    private String createRationalDiv(int max) throws Exception {
        List<Rational> raList = createTwoRandomRational(max);
        String math_questions;
        raResult = raList.get(0);
        Rational num1 = raList.get(1).multiply(raResult);
        math_questions = num1 + " ÷ " + raList.get(1) + " = ";
        return math_questions;
    }

    //生成小数加法的运算公式
    private String createDecimalAdd() {
        double number;
        douResult = 0.0;
        number = createRandomDecimal(2);
        douResult += number;
        String math_questions = String.valueOf(number);
        math_questions += " + ";
        number = createRandomDecimal(2);
        math_questions += String.valueOf(number);
        math_questions += " = ";
        douResult += number;
        douResult = Math.round(douResult * 100.0) / 100.0;
        return math_questions;
    }

    //生成小数减法的运算公式
    private String createDecimalSub() {
        double numberFirst, numberSecond;
        String math_questions;
        numberFirst = createRandomDecimal(2);
        numberSecond = createRandomDecimal(2);
        if (numberFirst >= numberSecond) {
            math_questions = numberFirst + " - " + numberSecond + " = ";
            douResult = numberFirst - numberSecond;
        } else {
            math_questions = numberSecond + " - " + numberFirst + " = ";
            douResult = numberSecond - numberFirst;
        }
        douResult = Math.round(douResult * 100.0) / 100.0;
        return math_questions;
    }

    //生成小数乘法的运算公式
    private String createDecimalMul() {
        int numberFirst;
        double numberSecond;
        String math_questions;
        numberFirst = createRandomNumber(10) + 1;
        numberSecond = createRandomDecimal(2);
        math_questions = numberFirst + " × " + numberSecond + " = ";
        douResult = numberFirst * numberSecond;
        douResult = Math.round(douResult * 100.0) / 100.0;
        return math_questions;
    }

    //生成小数除法的运算公式
    private String createDecimalDiv() {
        double numberFirst;
        int numberSecond;
        String math_questions;
        douResult = createRandomDecimal(1) + 1;
        BigDecimal res = new BigDecimal(douResult);
        numberSecond = createRandomNumber(10) + 1;
        BigDecimal number2 = new BigDecimal(numberSecond);
        numberFirst = (res.multiply(number2)).doubleValue();
        math_questions = String.format("%.2f", numberFirst) + " ÷ " + numberSecond + " = ";
        return math_questions;
    }

    //生成小数比较大小的运算公式
    private String createDecimalCmp() {
        Double number1 = createRandomDecimal(3);
        Double number2 = createRandomDecimal(3);
        int temp = number1.compareTo(number2);
        intResult = (temp > 0) ? 2 : (temp == 0 ? 3 : 1);//1:<  2: >  3:=
        String math_questions = "";
        math_questions += number1;
        math_questions += " ⚪ ";
        math_questions += number2;
        return math_questions;
    }

    //错题保存至文件
    public void ErrorSave(String openId) throws IOException {
        BufferedWriter writer = null;
        File file = new File("usr_error_formula" + File.separator + openId + File.separator + "Error.json");
        if(!file.exists()) {
            System.out.println("File doesn't exist");
            Path path = Paths.get("usr_error_formula" + File.separator + openId);
            Files.createDirectories(path);
            try {
                if (file.createNewFile()) {
                    System.out.println("目标文件不存在，创建成功！");
                } else {
                    System.out.println("目标文件不存在，创建失败！");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        String str = JSONArray.toJSONString(errorQuestionList);
        System.out.println(str);
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, false), StandardCharsets.UTF_8));
            writer.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null)
                    writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("文件写入成功！");
    }

    //读取错题列表
    public void ErrorLoad(String openId) {
        File file = new File("usr_error_formula" + File.separator + openId + File.separator + "Error.json");
        BufferedReader reader = null;
        StringBuilder errorLoad = new StringBuilder();
        //判断有无文件存在
        if (!file.exists()) {
            return;
        }
        //读取文件存放在String errorLoad中
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
            reader = new BufferedReader(inputStreamReader);
            String tempString;
            while ((tempString = reader.readLine()) != null) {
                errorLoad.append(tempString);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //将String errorLoad 转为列表
        System.out.println(errorLoad);
        errorQuestionList = JSON.parseObject(errorLoad.toString(), new TypeReference<ArrayList<TM>>() {
        });
    }

    //删除错题列表中的部分（全部）错题
    public void deleteError(String openId, List<Integer> ord4cancel) throws IOException {
        ErrorLoad(openId);
        Collections.sort(ord4cancel);
        int cnt = 0;
        for (int index : ord4cancel) {
            errorQuestionList.remove(index - cnt++);
        }
        ErrorSave(openId);
    }

    //添加错题
    public void addError(String openId, List<TM> errorList) throws IOException {
        ErrorLoad(openId);
        errorQuestionList.addAll(errorList);
        ErrorSave(openId);
    }

    public static void main(String[] args) throws Exception {
        Questions questions = new Questions(1);
        questions.mathQuestionsCreate(5, 5);
        System.out.println(questions.questionArrayList.get(0).getFormula());
        System.out.println(questions.questionArrayList.get(1).getFormula());
        System.out.println(questions.questionArrayList.get(2).getFormula());
        System.out.println(questions.questionArrayList.get(3).getFormula());
        System.out.println(questions.questionArrayList.get(4).getFormula());
        String openId = "o3zLF4jSKU1APAPJPQXVRW4-lh5Y";
        questions.ErrorLoad(openId);
        questions.ErrorSave(openId);
    }
}
